<?php
// $Id$

/**
* @file
* Provides everything needed for an online envelope budgeting system, incuding:
*		-The "envelope" node type
*
* For more about envelope budgeting see http://financialsoft.about.com/od/glossaryindexe/f/Envelope_Budget.htm
*/

/**
* Implementation of hook_node_info().
*/
function envelopes_online_node_info() {
	// We return an array since a module can define multiple node types.
	// We're only defining one node type, type 'envelope'.
	return array(
		'envelope' => array(
			'name' => t('Envelope'), // Required.
			'module' => 'envelopes_online', // Required.
			'description' => t('The core of the envelope budgeting system. Put money in these, then alocate it later.'), // Required.
			'has_title' => TRUE,
      'title_label' => t('Title'),
      'has_body' => TRUE,
      'body_label' => t('Description'),
      'min_word_count' => 1,
      'locked' => TRUE
		)
	);
}

/**
* Implementation of hook_init().
*/
function envelopes_online_init() {
	jquery_ui_add(array('ui.draggable', 'ui.droppable', 'ui.sortable', 'ui.datepicker'));
	drupal_add_js(drupal_get_path('module', 'envelopes_online') .'/envelopes_online.js');
}

/**
* Implementation of hook_perm().
*/
function envelopes_online_perm() {
	return array('create envelope', 'edit own envelope', 'edit any envelope', 'delete own envelope', 'delete any envelope');
}

/**
 * Implementation of hook_access().
 */
function envelopes_online_access($op, $node, $account) {
  $is_author = $account->uid == $node->uid;
  switch ($op) {
    case 'create':
      // Allow if user's role has 'create envelope' permission.
      return user_access('create envelope', $account);
    case 'update':
      // Allow if user's role has 'edit own envelope' permission and user is
      // the author; or if the user's role has 'edit any envelope' permission.
      return user_access('edit own envelope', $account) && is_author ||
        user_access('edit any envelope', $account);
    case 'delete':
      // Allow if user's role has 'delete own envelope' permission and user is
      // the author; or if the user's role has 'delete any envelope' permission.
      return user_access('delete own envelope', $account) && $is_author ||
        user_access('delete any envelope', $account);
  }
}

/**
* Implementation of hook_theme().
*/
function envelopes_online_theme() {
	return array(
		'envelopes_block' => array(
			'arguments' => array ('envelopes' => NULL),
		),
	);
}

/**
 * Implementation of hook_menu().
 */
function envelopes_online_menu() {
  $items['transactionform'] = array(
    'title' => 'Transaction Form',
    'page callback' => 'envelopes_online_page',
    'access arguments' => array('access content'),
  );
	$items['envelopes_online/ajax_sort_envelopes'] = array(
		'title' => 'Envelopes Online Sort Envelopes: AJAX Gateway',
		'page callback' => 'envelopes_online_sort_envelopes',
		'access arguments' => array('access content'),
		'type' => MENU_CALLBACK,
	);
  return $items;
}

/**
 * Menu callback.
 */
function envelopes_online_page() {
  $output = t('This page contains the transaction form.');

  // Return the HTML generated from the $form data structure.
  $output .= drupal_get_form('envelopes_online_transaction_form');
  return $output;
}

/**
 * Implementation of hook_form().
 */
function envelopes_online_form($node) {
  // Get metadata for this node type
  // (we use it for labeling title and body fields).
  // We defined this in envelope_node_info().
  $type = node_get_types('type', $node);

  $form['title'] = array(
    '#type' => 'textfield',
    '#title' => check_plain($type->title_label),
    '#required' => TRUE,
    '#default_value' => $node->title,
    '#weight' => -5,
    '#maxlength' => 255,
  );
  $form['body_filter']['body'] = array(
    '#type' => 'textarea',
    '#title' => check_plain($type->body_label),
    '#default_value' => $node->body,
    '#rows' => 3,
    '#required' => TRUE
  );
  $form['body_filter']['filter'] = filter_form($node->format);
  $form['cash'] = array(
    '#type' => 'textfield',
    '#title' => t('Cash in This Envelope'),
    '#required' => FALSE,
    '#default_value' => isset($node->cash) ? $node->cash : '0.00',
    '#weight' => 5
  );
  return $form;
}

/**
 * Implementation of hook_validate().
 */
function envelopes_online_validate($node) {
  // Cash value must be a number
  if (isset($node->cash) && !is_numeric($node->cash)) {
    $type = node_get_types('type', $node);
    form_set_error('cash', t('Please enter the amount of cash in this @type as a number, with no dollar sign.', array('@type' => $type->name)));
  }
}

/**
 * Implementation of hook_insert().
 */
function envelopes_online_insert($node) {
	// Check how many envelopes we have for this user, put this one at end of sort order
	global $user;
	$uid = $user->uid;
	$num_envelopes = db_result(db_query("SELECT count(*) FROM {node} WHERE uid = %d AND type = '%s'", $uid, 'envelope'));
	$sort_order = $num_envelopes;
  db_query("INSERT INTO {envelopes} (nid, vid, uid, cash, sort_order) VALUES (%d, %d, %d, %f, %d)",
    $node->nid, $node->vid, $uid, $node->cash, $sort_order);
}

/**
 * Implementation of hook_update().
 */
function envelopes_online_update($node) {
  if ($node->revision) {
    // New revision; treat it as a new record.
    envelopes_online_insert($node);
  }
  else {
    db_query("UPDATE {envelopes} SET cash = %f WHERE vid = %d",
      $node->cash, $node->vid);
  }
}

/**
 * Implementation of hook_delete().
 */
function envelopes_online_delete(&$node) {
  // Delete the related information we were saving for this node.
  db_query('DELETE FROM {envelopes} WHERE nid = %d', $node->nid);
}

/**
 * Implementation of hook_load().
 */
function envelopes_online_load($node) {
  return db_fetch_object(db_query('SELECT * FROM {envelopes} WHERE vid = %d',
    $node->vid));
}

/**
 * Define the 'add a transaction' form.
 */
function envelopes_online_transaction_form($form_state) {
	global $user;
  $form = array();

  // Register the form with ahah_helper so we can use it. Also updates
  // $form_state['storage'] to ensure it contains the latest values that have
  // been entered, even when the form item has temporarily been removed from
  // the form. So if a form item *once* had a value, you *always* can retrieve
  // it.
  ahah_helper_register($form, $form_state);

  // Determine the default value of the 'usage' select. When nothing is stored
  // in $form_state['storage'] yet, it's the form hasn't been submitted yet,
  // thus it's the first time the form is being displayed. Then, we set the
  // default transaction type to 'withdrawal'.
  if (!isset($form_state['storage']['transaction_info']['transaction_type'])) {
    $transaction_type_default_value = 'withdrawal';
  }
  else {
    $transaction_type_default_value =  $form_state['storage']['transaction_info']['transaction_type'];
  }

	$form['#ajax'] = array(
		'enabled' => TRUE
	);
  $form['date'] = array(
    '#title' => t('Date'),
    '#type' => 'textfield',
    '#description' => t('Date'),
		'#default_value' => date('n/j/Y'),
		'#size' => 10,
		'#maxlength' => 10,
		'#required' => TRUE,
  );
//  $form['transaction_info']['date'] = array(
//    '#title' => t('Date'),
//    '#type' => 'date',
//    '#description' => t('Date'),
//		'#default_value' => array(
//			'year' => date('Y', time()), 
//			'month' => date('n', time()), 
//			'day' => date('j', time()), 
//		),
//		'#required' => TRUE,
//  );
  $form['amount'] = array(
    '#type' => 'textfield',
		'#title' => t('Amount'),
		'#size' => 10,
		'#maxlength' => 13,
		'#required' => TRUE,
  );
  $form['description'] = array(
    '#type' => 'textfield',
		'#title' => t('Description'),
		'#size' => 40,
		'#maxlength' => 128,
		'#required' => FALSE,
  );
  $form['transaction_info'] = array(
    '#type'   => 'fieldset',
    '#title'  => t('Transaction Info'),
    '#prefix' => '<div id="transaction-info-wrapper">', // This is our wrapper div.
    '#suffix' => '</div>',
    '#tree'   => TRUE, // Don't forget to set #tree!
  );
  $form['transaction_info']['transaction_type'] = array(
		'#type' => 'radios',
		'#title' => t('Type of Transaction'),
		'#options' => array(
			'withdrawal' => t('Withdrawal'), 
			'deposit' => t('Deposit'), 
			'transfer' => t('Transfer')
		),
    '#default_value' => $transaction_type_default_value,
    '#ahah' => array(
      'event' => 'change',
      // This is the "magical path". Note that the parameter is an array of
      // the parents of the form item of the wrapper div!
      'path'    => ahah_helper_path(array('transaction_info')),
      'wrapper' => 'transaction-info-wrapper',
      'effect' => 'fade',
    ),
  );
  $form['transaction_info']['update_transaction_type'] = array(
    '#type'  => 'submit',
    '#value' => t('Update Transaction Type'),
    // Note that we can simply use the generic submit callback provided by the
    // ahah_helper module here!
    // All it does, is set $form_state['rebuild'] = TRUE.
    '#submit' => array('ahah_helper_generic_submit'),
    // We set the 'no-js' class, which means this submit button will be hidden
    // automatically by Drupal if JS is enabled.
    '#attributes' => array('class' => 'no-js'),
  );

  // If 'withdrawal' or 'transfer' is selected, then this form item will be displayed.
  if ($transaction_type_default_value == 'withdrawal' OR $transaction_type_default_value == 'transfer') {
		$form['transaction_info']['from'] = array(
			'#type' => 'select',
			'#title' => t('From Envelope'),
			'#options' => envelopes_online_get_envelopes($user->uid),
      // If the user switched to deposit, and then back, we remember the envelope
			// they were previously withrawing from
      '#default_value' => $form_state['storage']['transaction_info']['from'],
		);
	}
  // And if 'deposit' or 'transfer' is selected, then this form item will be displayed.
  if ($transaction_type_default_value == 'deposit' OR $transaction_type_default_value == 'transfer')  {
		$form['transaction_info']['to'] = array(
			'#prefix' => '<div id="target">',
			'#type' => 'select',
			'#title' => t('To Envelope'),
			'#options' => envelopes_online_get_envelopes($user->uid),
			'#suffix' => '</div>',
      // If the user switched to withdrawal, and then back, we remember the envelope
			// they were previously depositing to
      '#default_value' => $form_state['storage']['transaction_info']['to'],
		);
	}
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit Transaction'),
  );

  return $form;
}

/**
 * Stores transactions submitted via the transaction form to the db
 */
function envelopes_online_transaction_form_submit($form, &$form_state) {
	dsm($form);
	dsm($form_state);
	global $user;

	$date = strtotime($form_state['values']['date']);	// Convert to unix timestamp
	$amount = $form_state['values']['amount'];
	$description = $form_state['values']['description'];
	$from_envelope = $form_state['values']['transaction_info']['from'];
	$to_envelope = $form_state['values']['transaction_info']['to'];

	// Withdrawal
	if ($from_envelope AND !$to_envelope) {
		envelopes_online_withdraw($date, $amount, $description, $from_envelope, $user->uid);
	}
	// Deposit
	elseif ($to_envelope AND !$from_envelope) {
		envelopes_online_withdraw($date, $amount, $description, $to_envelope, $user->uid);
	}
	// Transfer
	else {
		envelopes_online_transfer($date, $amount, $description, $from_envelope, $to_envelope, $user->uid);
	}

	// Update amount show in envelopes block via ajax
}

/**
 * Withdraw money from an envelope
 */
function envelopes_online_withdraw($date, $amount = 0, $description = NULL, $from_envelope, $uid) {

	if (!$date) {
		$date = strtotime("now");
	}

	// Update envelope_transactions table
	$sql = "INSERT INTO {envelope_transactions} (date, amount, description, type, from_envelope) VALUES (%d, %f, '%s', '%s', %d)";
	$result = db_query(db_rewrite_sql($sql), $date, $amount, $description, 'w', $from_envelope);

	// Update envelopes table
	$sql = "UPDATE {envelopes} SET cash = cash - %d WHERE nid = %d";
	$result = db_query(db_rewrite_sql($sql), $amount, $from_envelope);

	watchdog('envelopes_online', 'User %uid withdrew $%amount from envelope %from_envelope.', 
		array('%uid' => $uid, '%amount' => $amount, '%from_envelope' => $from_envelope));
}

/**
 * Deposit money to an envelope
 */
function envelopes_online_deposit($date, $amount = 0, $description = NULL, $to_envelope, $uid) {

	if (!$date) {
		$date = strtotime("now");
	}

	// Update envelope_transactions table
	$sql = "INSERT INTO {envelope_transactions} (date, amount, description, type, to_envelope) VALUES (%d, %f, '%s', '%s', %d)";
	$result = db_query(db_rewrite_sql($sql), $date, $amount, $description, 'd', $to_envelope);

	// Update envelopes table
	$sql = "UPDATE {envelopes} SET cash = cash + %d WHERE nid = %d";
	$result = db_query(db_rewrite_sql($sql), $amount, $to_envelope);

	// Log the deposit
	watchdog('envelopes_online', 'User %uid deposited $%amount to envelope %to_envelope.', 
		array('%uid' => $uid, '%amount' => $amount, '%to_envelope' => $to_envelope));
}

/**
 * Transfer money from one envelope to another
 */
function envelopes_online_transfer($date, $amount = 0, $description = NULL, $from_envelope, $to_envelope, $uid) {

	if (!$date) {
		$date = strtotime("now");
	}

	// Update envelope_transactions table
	$sql = "INSERT INTO {envelope_transactions} (date, amount, description, type, from_envelope, to_envelope) VALUES (%d, %f, '%s', '%s', %d, %d)";
	$result = db_query(db_rewrite_sql($sql), $date, $amount, $description, 't', $from_envelope, $to_envelope);

	// Update envelopes table
	$sql = "UPDATE {envelopes} SET cash = cash - %d WHERE nid = %d";
	$result = db_query(db_rewrite_sql($sql), $amount, $from_envelope);
	$sql = "UPDATE {envelopes} SET cash = cash + %d WHERE nid = %d";
	$result = db_query(db_rewrite_sql($sql), $amount, $to_envelope);

	// Log the transfer
	watchdog('envelopes_online', 'User %uid transfered $%amount from envelope %from_envelope to envelope %to_envelope.', 
		array('%uid' => $uid, '%amount' => $amount, '%from_envelope' => $from_envelope, '%to_envelope' => $to_envelope));
}

/**
 * Returns an array of titles of envelopes created by the given user
 */
function envelopes_online_get_envelopes($uid) {
	$type = 'envelope';
	$status = 1; // In the node table, a status of 1 means published.
	$sql = "SELECT * FROM {node} WHERE type = '%s' AND status = %d AND uid = %d";
	$result = db_query(db_rewrite_sql($sql), $type, $status, $uid);
	while ($data = db_fetch_object($result)) {
		$node = node_load($data->nid);
		$envelopes[$node->nid] = $node->title;
	}
	return $envelopes;
}
	
/**
 * Implementation of hook_block().
 */
function envelopes_online_block($op = 'list', $delta = 0, $edit = array()) { 
  switch ($op) { 
    case 'list': 
      $blocks[0]['info'] = t('Your Envelopes'); 
      $blocks[0]['cache'] = BLOCK_NO_CACHE;
      return $blocks; 
    case 'view':
      $block = array();
      if ($delta == 0) {
        // Query the database for envelopes belonging to this user.
				global $user;
				$uid = $user->uid;
				$sql = "SELECT nid FROM {envelopes} WHERE uid = %d ORDER BY sort_order";
				$result = db_query(db_rewrite_sql($sql), $uid);
        $envelopes = array();
        while ($envelope = db_fetch_object($result)) {
          $envelopes[] = node_load($envelope->nid);
        }
        
        $block['subject'] = t('Your Envelopes');
        // theme the envelopes block
        $block['content'] = theme('envelopes_block', $envelopes);
      }
     return $block;
  } 
} 

/**
* Return a themed group of envelopes.
*
* @param $breadcrumb
* An array containing the breadcrumb links.
* @return a string containing the breadcrumb output.
*/
function theme_envelopes_block($envelopes) {
	$output .= '<ul id="sortable">';
	foreach ($envelopes as $envelope) {
		$output .= '<li id="sort_order_' . $envelope->nid . '" class="envelope" style="background-color: ' . $envelope->field_envelope_color[0]['value'] . '">';
			$output .= '<div class="envelope-edit">';
				$output .=  l('Edit', 'node/' . $envelope->nid . '/edit') ;
			$output .= '</div>';
			$output .= '<div class="envelope-title">';
				$output .=  $envelope->title ;
			$output .= '</div>';
			$output .= '<div class="envelope-cash">';
				$output .=  '$' . $envelope->cash ;
			$output .= '</div>';
		$output .= '</li>';
	}
	$output .= '</ul>';
	$output .= '<div id="data"></div>';

	return $output;
}

/**
* Function which saves the drag-and-drop ajax sorting of the envelopes 
* to the database.
*/
function envelopes_online_sort_envelopes() {
	$update_sort_orders 	= $_POST['sort_order'];
	$listing_counter = 1;
	foreach ($update_sort_orders as $update_sort_order) {
		$sql = 'UPDATE {envelopes} SET sort_order = %d WHERE nid = %d';
		db_query(db_rewrite_sql($sql), $listing_counter, $update_sort_order);
		$listing_counter = $listing_counter + 1;
	}
//	echo "DATA RECEIVED: <br />";
//	echo "<pre>";
//	print_r($_POST);
//	echo "</pre>";
}